package com.tools.common.utils.file;


import com.tools.common.web.HttpUtil;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;

/**
 * 文件处理工具类
 *
 * @author Administrator
 */
public class FileUtil {

    private static final Long ZERO_LONG = 0L;

    /**
     * @param inputStream
     * @param targetFile
     * @param totalSize
     * @throws IOException
     */
    public static void writeStreamToFile(InputStream inputStream, File targetFile, Long totalSize) throws IOException {
        if (!targetFile.getParentFile().exists()) {
            targetFile.getParentFile().mkdirs();
        }
        targetFile.createNewFile();
        RandomAccessFile randomAccessFile = new RandomAccessFile(targetFile, "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();
        ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream);
        fileChannel.transferFrom(readableByteChannel, ZERO_LONG, totalSize);
        fileChannel.close();
        randomAccessFile.close();
        readableByteChannel.close();
    }

    /**
     * 删除文件
     *
     * @param filePath 文件的完整路径
     * @return
     */
    public static boolean deleteFile(String filePath) {
        boolean flag = false;
        try {
            File file = new File(filePath);
            // 路径为文件且不为空则进行删除
            if (file.isFile() && file.exists()) {
                flag = file.delete();

                //判断当前路径下是否还存在文件或者文件夹 不存在则删除当前文件夹
                File parentFile = file.getParentFile();
                if (null != parentFile && parentFile.listFiles().length == 0) {
                    parentFile.delete();
                }
            }
            return flag;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;

    }

    /**
     * 删除空文件夹
     * @param directory 目录
     * @return
     */
    public static boolean deleteEmptyDirectory(String directory) {

        if (!directory.endsWith(File.separator)) {
            directory = directory + File.separator;
        }
        File directoryFile = new File(directory);

        // 判断directory对应的文件是否存在，或者是否是一个文件夹
        if (!directoryFile.exists() || !directoryFile.isDirectory()) {
            System.err.println("文件夹删除失败，文件夹不存在" + directory);
            return false;
        }
        int length = Objects.requireNonNull(directoryFile.listFiles()).length;
        if (length > 0) {
            System.err.println("文件夹删除失败，文件夹下存在文件" + directory);
            return false;
        }
        //删除当前文件夹
        boolean del = directoryFile.delete();
        if (!del) {
            System.err.println("文件夹删除失败" + directory);
            return false;
        }
        return true;
    }

    /**
     * 删除文件夹
     * 删除文件夹需要把包含的文件及文件夹先删除，才能成功
     *
     * @param directory 文件夹名
     * @return 删除成功返回true, 失败返回false
     */
    public static boolean deleteDirectory(String directory) {
        // directory不以文件分隔符（/或\）结尾时，自动添加文件分隔符，不同系统下File.separator方法会自动添加相应的分隔符
        if (!directory.endsWith(File.separator)) {
            directory = directory + File.separator;
        }
        File directoryFile = new File(directory);
        // 判断directory对应的文件是否存在，或者是否是一个文件夹
        if (!directoryFile.exists() || !directoryFile.isDirectory()) {
            System.out.println("文件夹删除失败，文件夹不存在" + directory);
            return false;
        }
        boolean flag = true;

        // 删除文件夹下的所有文件和文件夹
        File[] files = directoryFile.listFiles();

        // 循环删除所有的子文件及子文件夹
        for (File file : files) {
            // 删除子文件
            if (file.isFile()) {
                flag = deleteFile(file.getAbsolutePath());
            } else {  // 删除子文件夹
                flag = deleteDirectory(file.getAbsolutePath());
            }
            if (!flag) {
                break;
            }
        }

        if (!flag) {
            System.out.println("删除失败");
            return false;
        }
        // 最后删除当前文件夹
        if (directoryFile.delete()) {
            System.out.println("删除成功：" + directory);
            return true;
        } else {
            System.out.println("删除失败：" + directory);
            return false;
        }
    }

    /**
     * 文件上传
     * @param inputStream 文件输入流
     * @param filePath 保存的路径
     * @param fileName 保存的文件名
     * @return 0 成功
     * @throws IOException 异常信息
     */
    public static int uploadFile(InputStream inputStream, String filePath, String fileName) throws IOException {
        File f = new File(filePath);

        //如果根路径不存在 则创建
        if (!f.exists()) {
            boolean mkdirs = f.mkdirs();
            if (!mkdirs) {
                System.out.println("创建文件夹失败");
                return 1;
            }
        }

        FileOutputStream outStream = new FileOutputStream(filePath + File.separator + fileName);

        // 定义缓冲区，即为在内存开的内存空间是1024，也就是一次最多读取1024个字节
        byte[] bytes = new byte[1024];

        // 使用输入流从buffer里把数据读取出来 每次读取的字符串长度，如果为-1，代表全部读取完毕
        while ((inputStream.read(bytes)) != -1) {
            // 用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度  写入数据
            outStream.write(bytes);
        }
        inputStream.close();
        outStream.close();
        return 0;
    }

    /**
     * 根据channel拷贝文件
     * @param path1
     * @param path2
     */
    public static void copyByChannel(String path1, String path2) {

        FileChannel inputChannel = null;
        FileChannel outputChannel = null;
        try {
            inputChannel = new FileInputStream(path1).getChannel();
            outputChannel = new FileOutputStream(path2).getChannel();
            outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputChannel != null) {
                    inputChannel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (outputChannel != null) {
                    outputChannel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 获取文件的MD5
     *
     * @param inputStream
     * @return
     */
    public static String getMD5ByInput(InputStream inputStream) {
        BigInteger bi = null;
        try {
            byte[] buffer = new byte[8192];
            int len;
            MessageDigest md = MessageDigest.getInstance("MD5");
            while ((len = inputStream.read(buffer)) != -1) {
                md.update(buffer, 0, len);
            }
            byte[] b = md.digest();
            bi = new BigInteger(1, b);
        } catch (NoSuchAlgorithmException | IOException e) {
            e.printStackTrace();
        }
        return bi.toString(16);
    }

    /**
     * 下载文件 文件流的形式<br>
     * 这种方式是一次性读完文件 适合小文件
     * @param filePath 文件路径
     * @param response 响应对象
     * @throws IOException
     */
    public static void downOctetStream(String filePath, HttpServletResponse response) throws IOException {
        File file = new File(filePath);
        FileInputStream fileInputStream = new FileInputStream(file);
        // 将文件写入输入流
        InputStream fis = new BufferedInputStream(fileInputStream);
        byte[] buffer = new byte[fis.available()];
        fis.read(buffer);
        fis.close();

        response.reset();
        HttpUtil.addCorsResponseHeader(response);

        response.setCharacterEncoding("UTF-8");
        response.addHeader(HttpUtil.ResHeaders.CONTENT_DISPOSITION,
                HttpUtil.ResHeaders.CONTENT_DISPOSITION_VALUE_PREFIX_STR+ URLEncoder.encode(file.getName(), String.valueOf(StandardCharsets.UTF_8)));
        response.addHeader(HttpUtil.ResHeaders.CONTENT_LENGTH, "" + file.length());
        OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        response.setContentType(HttpUtil.ResHeaders.APPLICATION_OCTET_STREAM);
        outputStream.write(buffer);
        outputStream.flush();
    }


    /**
     * 读取文件内容
     * @param filePath 文件路径
     * @return 文件内容
     */
    public static String readFileContent(String filePath) {
        StringBuilder content = new StringBuilder();
        try {
            File file = new File(filePath);
            BufferedReader br = new BufferedReader(new FileReader(file));
            String line;
            while ((line = br.readLine()) != null) {
                content.append(line).append("\n");
            }
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return content.toString();
    }
}
